#!/usr/bin/env pythonw

import sys
import os

try:
    import pygtk
    pygtk.require('2.0')
except:
    pass
try:
    import gtk
    import gtk.glade
except:
    sys.stderr.write("ERROR: The GTK+ toolkit and PyGTK extension are required to run this program.\n")
    sys.exit(1)

import preferences
import workflow

class MainWindow(object):
    def __init__(self):
        self.widgetLayout = gtk.glade.XML("assets/layout/mainLayout.glade")
        self.window = self.widgetLayout.get_widget("MainWindow")
        self.inputsDisplay = self.widgetLayout.get_widget("workflowInputs")
        self.componentsDisplay = self.widgetLayout.get_widget("workflowComponents")
        self.outputsDisplay = self.widgetLayout.get_widget("workflowOutputs")
        self.title = self.widgetLayout.get_widget("workflowTitle")
        self.workflowPosition = 0
        connectionList = {
                          "on_fileItemQuit_activate": gtk.main_quit,
                          "on_mainWindow_destroy": gtk.main_quit,
                          "on_fileItemOpen_activate": self.openWorkflow,
                          "on_helpItemAbout_activate": self.aboutCW,
                          "on_helpItemHelp": self.showHelp,
                          "on_toolbarOpen_clicked": self.openWorkflow,
                          "on_toolbarReset_clicked": self.resetWorkflow,
                          "on_toolbarStep_clicked": self.stepWorkflow,
                          "on_toolbarRun_clicked": self.runWorkflow
                          }
        self.widgetLayout.signal_autoconnect(connectionList)
        
    @property
    def workflowSteps(self):
        try:
            return self.__workflowSteps
        except AttributeError:
            input_values = {}
            for k in self.workflow.inputs:
                input_values[k] = self.inputs[k].entry.get_text()
            self.__workflowSteps = self.workflow.steps(input_values)
            return self.__workflowSteps
        
    def openWorkflow(self, widget):
        open_dialog = gtk.FileChooserDialog(title="Open Workflow", 
                                            parent=self.window, 
                                            action=gtk.FILE_CHOOSER_ACTION_OPEN,
                                            buttons=(gtk.STOCK_CANCEL,
                                                     gtk.RESPONSE_CANCEL,
                                                     gtk.STOCK_OPEN,
                                                     gtk.RESPONSE_OK)
                                            )
        open_dialog.set_default_response(gtk.RESPONSE_OK)
        open_dialog.set_current_folder(os.path.abspath(os.curdir) + "/workflows")
        filter = gtk.FileFilter()
        filter.set_name("Workflow Files")
        filter.add_pattern("*.yml")
        open_dialog.add_filter(filter)
        response = open_dialog.run()
        if response == gtk.RESPONSE_OK:
            self.workflow = workflow.Workflow(open_dialog.get_filename())
            self.showWorkflow()
        open_dialog.destroy()
    
    def aboutCW(self, widget):
        about_cryptoworkflow = gtk.AboutDialog()
        about_cryptoworkflow.set_name("CryptoWorkflow")
        about_cryptoworkflow.set_version("0.1a")
        about_cryptoworkflow.set_copyright("Copyright (C) 2008 Craig Radcliffe")
        about_cryptoworkflow.set_license("".join(open("copying.txt").readlines()))
        about_cryptoworkflow.set_website("http://code.google.com/p/cryptoworkflow/")
        about_cryptoworkflow.set_website_label("CryptoWorkflow Website")
        about_cryptoworkflow.set_authors(["Craig Radcliffe"])
        about_cryptoworkflow.set_program_name("CryptoWorkflow")
        about_cryptoworkflow.run()
        about_cryptoworkflow.destroy()
    
    def showHelp(self, widget):
        pass
    
    def resetWorkflow(self, widget):
        try:
            del(self.__workflowSteps)
        except AttributeError:
            pass
        else:
            for input in self.inputs:
                self.inputs[input].entry.set_text("")
            for step in self.workflowStepsDisplay:
                for output in step.components:
                    step.components[output].entry.set_text("")
    
    def stepWorkflow(self, widget):
        pass
    
    def runWorkflow(self, widget):
        try:
            del(self.__workflowSteps)
        except AttributeError:
            pass
        try:
            for step in self.workflowStepsDisplay:
                results = self.workflowSteps.next()
                for i,j in results.items():
                    step.components[i].entry.set_text(j)
        except ValueError, (message, parameter):
            error_box = gtk.MessageDialog(parent=None, 
                                          type=gtk.MESSAGE_ERROR, 
                                          buttons=gtk.BUTTONS_CLOSE,
                                          message_format=message)
            error_box.run()
            error_box.destroy()
    
    def showWorkflow(self):
        self.title.set_label("<big><b>"+self.workflow.title+"</b></big>")
        self.initializeInputs()
        self.initializeComponents()
            
    def initializeInputs(self):
        self.inputs = {}
        for input in self.workflow.inputs:
            self.inputs[input] = LabelEntry(input,
                                                    expand=False,
                                                    fill=False)
            self.inputsDisplay.pack_start(self.inputs[input],
                                           expand=False,
                                           fill=False)
            self.inputs[input].show()

    def initializeComponents(self):
        self.workflowStepsDisplay = []
        for operation in self.workflow.operations:
            self.workflowStepsDisplay.append(GraphicalWorkflowStep(operation['name'],
                                             operation['outputs']))
        [self.componentsDisplay.pack_start(i) for i in self.workflowStepsDisplay]
        [i.show() for i in self.workflowStepsDisplay]

        
class LabelEntry(gtk.VBox):
    """
    A class to construct an Entry box with a Label.
    """
    def __init__(self, title, expand=True, fill=True, padding=5, editable=True):
        gtk.VBox.__init__(self)
        self.label = gtk.Label(title)
        self.entry = gtk.Entry()
        self.entry.set_editable(editable)
        self.entry.set_width_chars(30)
        self.pack_start(self.label, expand=expand, fill=fill, padding=padding)
        self.pack_start(self.entry, expand=expand, fill=fill, padding=padding)
    
    def show(self):
        self.label.show()
        self.entry.show()
        super(LabelEntry, self).show()

        
class GraphicalWorkflowStep(gtk.HBox):
    """
    A class to construct a graphical view of a workflow step, including prediction
    fields.
    """
    def __init__(self, operation, step_outputs, expand=True, fill=True, padding=5):
        gtk.HBox.__init__(self)
        self.__predictions = {}
        self.__components = {}
        self.__predictionsDisplay = gtk.VBox()
        self.__componentsDisplay = gtk.VBox()
        self.pack_start(self.__predictionsDisplay, expand=expand, fill=fill, padding=padding)
        self.pack_start(self.__componentsDisplay, expand=expand, fill=fill, padding=padding)
        for output in step_outputs:
            self.__predictions[output] = LabelEntry(output)
            self.__predictions[output].entry.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("blue"))
            self.__predictionsDisplay.pack_start(self.__predictions[output],
                                                 expand=expand,
                                                 fill=fill,
                                                 padding=padding)
            self.__components[output] = LabelEntry(output, editable=False)
            self.__componentsDisplay.pack_start(self.__components[output], expand=expand,
                                                fill=fill, padding=padding)
    
    @property
    def predictions(self):
        return self.__predictions
    @property
    def components(self):
        return self.__components
    
    def show(self):
        [self.__predictions[i].show() for i in self.__predictions]
        [self.__components[i].show() for i in self.__components]
        self.__predictionsDisplay.show()
        self.__componentsDisplay.show()
        super(GraphicalWorkflowStep, self).show()
        

def main(*args, **kwargs):
    """
    The main program function. Called when file is executed directly.
    """
    userPreferences = preferences.Preferences()
    
    cwapp = MainWindow()
    gtk.main()
    
    userPreferences.savePrefs()

# Execute main if file executed directly.
if __name__ == "__main__":
    main()